﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace hconnect {
    public class ModbusUtil {
        public static byte[] GetBytes(short value) {
            return Reverse(BitConverter.GetBytes(value));
        }
        public static byte[] GetBytes(ushort value) {
            return Reverse(BitConverter.GetBytes(value));
        }
        public static byte[] GetBytes(int value) {
            return Reverse(BitConverter.GetBytes(value));
        }
        public static byte[] GetBytes(float value) {
            return Reverse(BitConverter.GetBytes(value));
        }
        public static byte[] GetBytes(double value) {
            return Reverse(BitConverter.GetBytes(value));
        }
        public static short GetShort(byte[] data) {
            return BitConverter.ToInt16(Reverse(data) ,0);
        }
        public static ushort GetUShort(byte[] data) {
            return BitConverter.ToUInt16(Reverse(data) ,0);
        }
        public static int GetInt(byte[] data) {
            return BitConverter.ToInt32(Reverse(data) ,0);
        }

        public static int int32(byte[] b ,int begin) {
            if( b == null ) {
                return 0;
            }
            byte[] a = new byte[]
                  {

                            b[begin+1],
                            b[begin],
                            b[begin+3],
                            b[begin+2],
                  };
            return BitConverter.ToInt32(a ,0);
        }
        public static float GetFloat(byte[] data) {
            return BitConverter.ToSingle(Reverse(data) ,0);
        }
        public static double GetDouble(byte[] data) {
            return BitConverter.ToDouble(Reverse(data) ,0);
        }
        static byte[] Reverse(byte[] data) {
            Array.Reverse(data);
            return data;
        }
        public static void CheckErr(byte[] result ,short transaction_id ,byte _identifier) {
            if( result == null || result.Length == 0 ) {
                throw new IOException("Received no data slave exception response");
            }

            String v = "";
            for(int i=0;i<  result.Length ;i++) {
                v += result[i].ToString("X2") + " ";
            }
            if ( result.Length < 9 ) {
                throw new IOException(v+"Received WRONG_MESSAGE_LEN slave exception response" + result.Length);
            }



            if( result[7] > 128 && result[8] != 0 ) {
                bool flag5 = Enum.IsDefined(typeof(ExceptionCode) ,result[8]);
                if( flag5 ) {
                    throw new IOException(v + "Received ExceptionCode slave exception response" + (( ExceptionCode ) result[8]).ToString());
                }
            }
            short id = ( short ) GetUShort(result.Take(2).ToArray<byte>());
            if( transaction_id != id ) {
                throw new IOException(v + " WRONG_TRANSACTION_ID  exception response" + id);
            }
            bool flag7 = GetUShort(new byte[]
            {
                        result[2],
                        result[3]
            }) > 0;
            if( flag7 ) {
                throw new IOException(v + " WRONG_PROTOCOL_ID  exception response" + id);
            }
            ushort uShort = GetUShort(new byte[]
            {
                        result[4],
                        result[5]
            });
            bool flag8 = result.Length - 7 + 1 < ( int ) uShort;
            if( flag8 ) {
                throw new IOException(v + " WRONG_MESSAGE_LEN  exception response");
            }
            if( _identifier != result[6] ) {
                throw new IOException(v + " WRONG_RESPONSE_UNIT_ID  exception response");
            }
        }
        public static byte[] readHoldingRegistersHeader(byte identifier ,ushort start_address ,ushort len) {
            ushort message_len = 6;
            if( len < 1 ) {
                throw new Exception("modbus read len less");
            };
            if( len < 1 ) {
                throw new Exception("modbus read len too long");
            };
            List<byte> list = new List<byte>(7);
            list.InsertRange(0 ,GetBytes(( short ) 0));//this.transaction_id
            list.InsertRange(2 ,GetBytes(( short ) 0));
            list.InsertRange(4 ,GetBytes(( short ) message_len));
            list.Insert(6 ,identifier);
            list.Add(3);
            list.AddRange(GetBytes(( short ) start_address));
            list.AddRange(GetBytes(( short ) len));
            byte[] result = list.ToArray();
            return result;
        }
        public static byte[] BuildMBAPHeader(byte identifier ,ushort message_len) {
            List<byte> list = new List<byte>(7);
            list.InsertRange(0 ,GetBytes(( short ) 0));//this.transaction_id
            list.InsertRange(2 ,GetBytes(( short ) 0));
            list.InsertRange(4 ,GetBytes(( short ) message_len));
            list.Insert(6 ,identifier);
            return list.ToArray();
        }
        public static byte[] BulidReadCoilsTelex(ushort start_address ,ushort len) {
            bool flag2 = len > 2000;
            if( flag2 ) {
                return null;
            }
            List<byte> list = new List<byte>();
            list.Add(1);
            list.AddRange(GetBytes(( short ) start_address));
            list.AddRange(GetBytes(( short ) len));
            return list.ToArray();
        }
        public static byte[] BulidReadHoldingRegistersTelex(ushort start_address ,ushort len) {
            List<byte> list = new List<byte>();
            list.Add(3);
            list.AddRange(GetBytes(( short ) start_address));
            list.AddRange(GetBytes(( short ) len));
            byte[] result = list.ToArray();
            return result;
        }
        public static String toString(byte[] b ,int begin ,int len) {
            byte[] bytes = getByte(b ,begin ,len);
            return toString(bytes);
        }
        public static String toString(byte[] b) {
            byte[] bytes = new byte[b.Length];
            for( int i = 1;i < b.Length;i += 2 ) {
                bytes[i - 1] = b[i];
                bytes[i] = b[i - 1];
            }
            if( b.Length % 2 == 1 ) {
                bytes[b.Length - 1] = b[b.Length - 1];
            }

            int k = 0;
            for( ;k < bytes.Length;k++ ) {
                if( bytes[k] == 0 ) {
                    break;
                }
            }
            byte[] r = getByte(bytes ,0 ,k);


            String user = System.Text.Encoding.Default.GetString(r);
            return user;

        }
        public static byte[] getByte(byte[] statebyte ,int begin ,int len) {
            byte[] bytes = new byte[len];
            for( int i = begin;i < len + begin;i++ ) {
                bytes[i - begin] = statebyte[i];
            }
            return bytes;
        }


    }
    public enum ExceptionCode :byte {
        NO_ERROR = 0,
        IllegalFunction = 1,
        IllegalDataAddress = 2,
        IllegalDataValue = 3,
        SlaveDeviceFalure = 4,
        Acknowledge = 5,
        SlaveDeviceBusy = 6,
        MemoryPartiyError = 8,
        GatewayPathUnavailable = 10,
        GatewayTargetDeviceFailedToRespond = 11
    }
}
